來到我們文章的第三天,看著小任務的題目們,今天看起來就是繼續回顧了 ( 喂!
這兩個小任務需要參考 JavaScript 的「淺拷貝」與「深拷貝」的觀念。這邊簡單說明一下:
淺拷貝是共用同一個記憶體空間,因此當有一方改變,另一方也會一起改變;深拷貝則是直接拷貝位址,因此是兩個不同的記憶體空間,無法改變原先的程式碼狀態。
任務 ①
1-1. 請問以下的輸出結果為何?
let obj = {
title: '錢錢',
amounts: 66666,
}
let objNew = obj;
objNew.amounts = 123;
console.log(obj.amounts); // 輸出結果為何?
console.log(obj === objNew); // 輸出結果為 true 還是 false?
以輸出結果來看,很明顯是做了淺拷貝,當 objNew.amounts = 123;
的時候,obj.amounts
也一併被改變,他們共用同一個記憶體空間。
123
true
1-2. 如果希望 console.log(obj === objNew);
的結果為 false
,則可以如何修改?
let obj = {
title: '錢錢',
amounts: 66666,
}
let objNew = { ...obj };
// 或 let objNew = Object.assign({}, obj);
objNew.amounts = 123;
console.log(obj.amounts); // 輸出結果為何?
console.log(obj === objNew); // 輸出結果為 true 還是 false?
使用 ES6 的功能 operator,利用 …obj
的方式展開,使 obj 只有一層的情況時成為深拷貝,於是輸出以下結果:
66666
false
任務 ② ****( 陷阱題,需要用深拷貝處理 )
2-1. 請問以下的輸出結果為何?
let obj = {
title: '錢錢',
amounts: 66666,
innerObj: {
title: '私房錢',
amounts: 1000
}
}
let objNew = {...obj};
console.log(obj === objNew); // 輸出結果為 true 還是 false?
objNew.innerObj.amounts = 2000;
console.log(obj.innerObj.amounts); // 輸出結果為何?
false
2000
上面的註解有說到,深拷貝是直接拷貝位址,所以在不同記憶體空間的情況下,照理來說我們應該是無法修改 objNew.innerObj.amounts
,但為什麼還是改到了?因為這種展開方式只會複製表層而已,如果物件超過一層,深層的內容仍然是共用同一個記憶體。
這裡也給大家介紹一下 Object.assign(target, source)
,他的作用是將來源的 object 分派給指定的物件,但是以下面的結果來看,他仍然無法做最全面的深拷貝,因此在這邊我覺得就是知道一下有這個東西就可以了。
let obj = {
title: '錢錢',
amounts: 66666,
innerObj: {
title: '私房錢',
amounts: 1000
}
}
let objNew = Object.assign({}, obj);
console.log(obj === objNew); // 輸出結果為 true 還是 false?
objNew.innerObj.amounts = 2000;
console.log(obj.innerObj.amounts); // 輸出結果為何?
false
2000
2-2. 如果希望調整 objNew.innerObj
時不會影響到 obj
,則可以如何修改?
let obj = {
title: '錢錢',
amounts: 66666,
innerObj: {
title: '私房錢',
amounts: 1000
}
}
let objNew = JSON.parse(JSON.stringify(obj))
console.log(obj === objNew); // 輸出結果為 true 還是 false?
objNew.innerObj.amounts = 2000;
console.log(obj.innerObj.amounts); // 輸出結果為何?
真正的深拷貝方法終於出現了XD,使用 JSON.stringify(obj)
以及 JSON.parse(JSONString)
,將物件轉成字串再轉成物件,便可以確保出來一個新的物件,且不同的記憶體位置。
false
1000
任務:
console.log
let saySomething = '小姐一個人嗎 :D'
(function() {
console.log(saySomething);
});
以上程式碼執行之後會回傳:
"小姐一個人嗎 :D" is not a function
這是因為運行時,被認為是同一行,像這樣:
let saySomething = '小姐一個人嗎 :D'(function() {
console.log(saySomething);
});
對於分號加或不加的部分,自己比較沒有那個疑慮,因為我是分號魔人 ( ? ),真的很愛一結束就來個分號。
任務:
let name = '小明';
const age = 16;
let person = {
name: '小明',
}
const wallet = {
money: 1000
}
const dessert = ['cake', 'ice-cream'];
/* 請問以下程式碼哪些會報錯? */
name = '小美';
age = 17;
person.name = '大明';
wallet.money = 1100;
wallet = {};
dessert.push('fruit');
dessert = ['chocolate'];
// 以下三個錯誤回報原因皆為 const 不能重新賦予
age
wallet = {};
dessert = ['chocolate'];
任務:
請將以下程式碼簡化為箭頭函式 ( 不影響結果的情況下進行最大簡化 )
// 題目一
function sum(a, b) {
let c = a + b;
return c;
}
console.log(sum(5, 6));
// 題目二
function square(num) {
return num * num;
}
console.log(square(5))
// 題目三
setTimeout(function() {
console.log('延遲 1 秒');
}, 1000);
// 題目四
let arr = [1, 2, 3];
let arrNew = arr.map(function(item, i) {
return item * i;
});
console.log(arrNew);
// 題目五
let obj = {
fn: function fn2(a) {
return a * a;
}
}
console.log(obj.fn(10));
解答:
// 題目一
const sum = (a, b) => {
let c = a + b;
return c
}
console.log(sum(5, 6));
// 題目二
const square = num => num * num;
console.log(square(5))
// 題目三
setTimeout(() => {
console.log('延遲 1 秒');
}, 1000);
// 題目四
let arr = [1, 2, 3];
let arrNew = arr.map((item, i) => item * i);
console.log(arrNew);
// 題目五
let obj = {
fn: a => a * a
}
console.log(obj.fn(10));
任務 ① ****依據提示將以下程式碼用解構方式達成目標
// 題目一: 請使用解構,取出 name 及 age 的變數
const person = {
name: '小明',
age: 16
}
console.log(name, age);
// 題目二: 請問以下 console.log 的輸出結果為何?
let [a, b, c = 4, d = 'New', e] = [1, 2, 3];
console.log(a, b, c, d, e);
解答:
// 題目一
const { name, age } = person;
console.log(name, age); // 小明 16
// 題目二
let [a, b, c = 4, d = 'New', e] = [1, 2, 3];
// a 是被右邊賦值 1,b 被右邊賦值 2,c 被右邊賦值 3,d 新增並賦值 'New'
// e 沒有任何東西所以是 undefined
console.log(a, b, c, d, e); // 1, 2, 3, 'New', undefined
任務 ② ****依據提示將以下程式碼用展開方式達成目標
// 題目一: 請使用展開將 arr 的內容併入 arrNew
let arr = [1, 2, 3];
let arrNew = [?, 4, 5, 6];
console.log(arrNew);
// 題目二: 請使用展開將 restInfo 的內容併入 MingInfo
let restInfo = {
sex: '男生',
height: 178
}
let MingInfo = {
name: '小明',
age: 20,
}
解答:
// 題目一
let arr = [1, 2, 3];
let arrNew = [...arr, 4, 5, 6];
console.log(arrNew); // [1, 2, 3, 4, 5, 6]
// 題目二
let restInfo = {
sex: '男生',
height: 178
}
let MingInfo = {
name: '小明',
age: 20,
...restInfo
}
console.log(MingInfo); // {name: '小明', age: 20, sex: '男生', height: 178}
任務 ③ ****請修改以下程式碼,透過參數預設值、其餘參數的方式完成此範例。
function getMoney(/* 填入程式碼 */) {
return money;
}
let myMoney = getMoney();
// fruits 是一個陣列
function buySomething(/* 填入程式碼 */) {
if(fruits.length > 2) {
myMoney -= 200;
}else {
myMoney -= 100;
}
console.log(`小明剩下 ${myMoney} 元`);
}
buySomething('lemon', 'watermelon', 'kiwi');
buySomething('lemon', 'watermelon');
解答:
function getMoney(money = 500) {
return money;
}
let myMoney = getMoney();
// 展開代入一個陣列
function buySomething(...fruits) {
if(fruits.length > 2) {
myMoney -= 200;
}else {
myMoney -= 100;
}
console.log(`小明剩下 ${myMoney} 元`);
}
buySomething('lemon', 'watermelon', 'kiwi'); // 結果為 "小明剩下 300 元"
buySomething('lemon', 'watermelon'); // 結果為 "小明剩下 400 元"
有關 JavaScript 的回顧小任務就到今天,明天開始就讓我們一起練習 bootstrap 語法的運用吧,當然對這些語法已經熟到不能再熟的朋友們,也可以直接跳過這幾天了(笑
那麼夜已深,晚安了各位。